package cn.sinjet.model.carsystem;

import java.text.DecimalFormat;
import java.util.List;
import java.util.Locale;


import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import com.mgroup.wazehelper.R;
import cn.sinjet.carassist.SinjetApplication;
import cn.sinjet.communication.bluetooth.BluetoothModel;
import cn.sinjet.model.carassist.AppModel;
import cn.sinjet.model.carassist.CarAssistService;
import cn.sinjet.model.carsystem.OBDData.XJPIDDATA;
import cn.sinjet.model.mcuupgrade.McuUpgradeModel;
import cn.sinjet.prototol.codec.ToDevNaviCodec;
import cn.sinjet.prototol.codec.ToureDevCodec;
import cn.sinjet.utils.Data;
import cn.sinjet.viewmodel.ViewEvent;
import cn.sinjet.viewmodel.ViewModel;

public class DeviceModule{
	private static String tag = "DeviceModule";
	static final int MSG_NO_INFO_TIMEOUT = 100;
    private Context context = null;
    final static int TEMPERATURE_RANGE_MIN = 0;
    final static int TEMPERATURE_RANGE_MAX = 112;
    final static float VOLTAGE_RANGE_MIN = 10.0f;
    final static float VOLTAGE_RANGE_MAX = 15.0f;
    
//	private BaiduNaviClient baiduNaviClient = null;
	private ToDevNaviCodec mNaviCodec = new ToDevNaviCodec();
	CarModel  models;
	private boolean isTimeSync = false;
	private OBDData mObdData = null;//new PidData();
	private ToureDevCodec  mToureCodec = null;
	
    public DeviceModule(CarModel  models){
    	this.context = SinjetApplication.getInstance();
    	this.models = models;
    	mObdData = new OBDData();
    	/*if(keepAliveThread != null){
			keepAliveThread.setConnected(false);
			keepAliveThread.interrupt();
			keepAliveThread = null;
		}*/
    	
		/*if(keepAliveThread == null){
			Log.d("BT","create thread to send keepalive");
			keepAliveThread = new KeepAliveThread();
			keepAliveThread.setConnected(true);
			keepAliveThread.start();
		}*/
    }

    public OBDData getObdData(){
    	if(mObdData == null) mObdData = new OBDData();
        return mObdData;
    }
    
    
	/*class KeepAliveThread extends Thread{
		  private boolean isConnected = false;
		  private boolean bTryConnectBaidu = true;
		  public void setConnected(boolean isConnected){
			  this.isConnected = isConnected;
		  }
	     @Override
	    public void run() {
	    	// TODO Auto-generated method stub
	    	//super.run();
	    	 while(isConnected){
	    		 try{
//			            mNaviCodec.notifyIsNaviRunning((byte)isNavigating());
						mToureCodec.sendHeartbeat();
						bTryConnectBaidu = !bTryConnectBaidu;
						if(bTryConnectBaidu) connectBaiduNavi();
			           if(!isTimeSync){
			        	    Thread.sleep(500);
			        	    syncTime();
			           }
					   Thread.sleep(3000);
				   }catch(Exception e){
					   e.printStackTrace();
					   Thread.currentThread().interrupt();
				   }
	    	 }
	    }
	}*/
	
	
	public void sendHeartbeat(){
		if(mToureCodec == null)
			mToureCodec = new ToureDevCodec();
		mToureCodec.sendHeartbeat();
	}
	
//	KeepAliveThread keepAliveThread = null;
	int initOKFromMcu = 0;
	public void onBTConnected() {
		// TODO Auto-generated method stub
		if(mToureCodec == null) mToureCodec = new ToureDevCodec();
		initOKFromMcu = 0;
		
		handleAppInitOK();
//		mToureCodec.sendInit(0x01);
		Message msg = new Message();
		msg.what = CarAssistService.MSG_BT_CONNECTED;
		SinjetApplication.getInstance().getMsgClient().sendMsgToService(msg);

		syncTime();
//		m_appInitOkHandler.postDelayed(m_appInitOkRunnable,1000);//keep sending every 1 second until it get response
		
	}
	
	public void handleAppInitOK(){
		if (initOKFromMcu != 1 && BluetoothModel.getInstance().isConnected()) {
			Log.d("ing", "send initOK");
			mToureCodec.sendInit(0x01);
			Handler msgHandler = SinjetApplication.getInstance().getMsgClient().getMsgHandler();
			if(msgHandler != null)
				msgHandler.sendEmptyMessageDelayed(CarAssistService.MSG_SEND_INIT_OK, 1000);
		}
	}
	
	
	Handler m_appInitOkHandler = new Handler();
	Runnable m_appInitOkRunnable = new Runnable() {
		public void run() {
		// TODO Auto-generated method stub
		if (initOKFromMcu != 1 && BluetoothModel.getInstance().isConnected()) {
			Log.d("ing", "send initOK");
			mToureCodec.sendInit(0x01);
		     m_appInitOkHandler.postDelayed(m_appInitOkRunnable, 1000);
		  }
		}
	};
	
	
	public void onBTDisconnected(){
		/*if(keepAliveThread != null){
			keepAliveThread.setConnected(false);
			keepAliveThread.interrupt();
			keepAliveThread = null;
		}*/
		Message msg = new Message();
		msg.what = CarAssistService.MSG_BT_DISCONNECTED;
		SinjetApplication.getInstance().getMsgClient().sendMsgToService(msg);
		
		isTimeSync = false;
	}
    
	
	public void syncTime(){
		if(!isTimeSync){
		     mNaviCodec.sendCurrentTime();
		     Message msg = new Message();
			 msg.what = CarAssistService.MSG_SYNC_TIME; 
			 Handler msgHandler = SinjetApplication.getInstance().getMsgClient().getMsgHandler();
			 if(msgHandler != null)
				 msgHandler.sendMessageDelayed(msg, 500);
		}
	}
	
	public void connectBaiduNavi() {
		// TODO Auto-generated method stub
//		if(baiduNaviClient == null)
//			   baiduNaviClient = new BaiduNaviClient(context);
//		if(baiduNaviClient == null)  return;
//		if(!baiduNaviClient.isConnectedWithBaiduNavi())
// 		   baiduNaviClient.connectBaiduNavi();
	}

	
	public void tryToConnectBaiduNavi() {
		// TODO Auto-generated method stub
//		if(baiduNaviClient == null)
//			   baiduNaviClient = new BaiduNaviClient(context);
//		if(baiduNaviClient.startBaiduNavi()){
//			connectBaiduNavi();
//			SinjetApplication.getInstance().showFloatMenu(true);
//		}
	}


	public void onRecvMsg(byte[] buf) {
		// TODO Auto-generated method stub
//		final StringBuilder stringBuilder = new StringBuilder(buf.length);
//		for (byte byteChar : buf)
//			stringBuilder.append(String.format("%02X ", byteChar));
//		Log.i("BT","recvMessage in handle thread: "+ stringBuilder.toString());
		switch(buf[0]){
		case 0x01:
			onRecvHudMsg(buf);
			break;
		case 0x03:
			onRecvCommonMsg(buf);
			break;
		}
	}
   

//	String mStrVinCode = "";
	String mStrVinFirstHalf = "";
	String mStrVinSecondHalf = "";
	public int mRotate = 0;
	private void onRecvCommonMsg(byte[] buf) {
		// TODO Auto-generated method stub
		int cmd = buf[1];
		switch(cmd){
		case 0x00:
//			mNaviCodec.setIsHudDev(false);
			if(buf[2] == 0x01){
			    initOKFromMcu = 1;
//			    if(!mNaviCodec.isNaviDev())
			    mToureCodec.sendConnectECU(0x00);
			}
			break;
		case 0x01:
			getDevType(buf[2]&0xFF);
			break;
		case 0x02:{
			getOBDProtocolType(buf[2]&0xFF);
		}break;
		case 0x03:{
			if (buf[2] == 0)// front
			{
				mStrVinFirstHalf = "";
				byte[] szVinCode = new byte[9];
				System.arraycopy(buf, 3, szVinCode, 0, 9);
				String strVinCode = new String(szVinCode);
				mStrVinFirstHalf = strVinCode;
				System.out.println("f strVinCode = " + strVinCode);
			} else if (buf[2] == 1)// back
			{
				mStrVinSecondHalf = "";
				byte[] szVinCode = new byte[8];
				System.arraycopy(buf, 3, szVinCode, 0, 8);
				String strVinCode = new String(szVinCode);
				mStrVinSecondHalf = strVinCode;
				System.out.println("b strVinCode = " + strVinCode
						+ " mSstrVinCode = " + mStrVinFirstHalf+mStrVinSecondHalf);
                 ViewModel.getIns().setViewProperty(R.id.car_vin_code_value, mStrVinFirstHalf+mStrVinSecondHalf);
                 AppModel.getInstance().setCarVIN(mStrVinFirstHalf+mStrVinSecondHalf);
			}
		}break;
		case 0x06:{
			int leftFrontDoor = Data.bit0(buf[2]);
			int rightFrontDoor = Data.bit1(buf[2]);
			int leftRearDoor = Data.bit2(buf[2]);
			int rightRearDoor = Data.bit3(buf[2]);
			
			int handBrake = Data.bit4(buf[2]);
			int trunk = Data.bit5(buf[2]);
			int seatbelt = Data.bit7(buf[2]);
			int gear = Data.byteH4(buf[4]);
			int gearNum = Data.byteL4(buf[4]);
			handleDoorState(leftFrontDoor,rightFrontDoor,leftRearDoor,rightRearDoor,trunk);
			handCarInfo(handBrake,seatbelt,gear,gearNum);
		}break;
		case 0x10:{
			int voltage = ((buf[2] & 0xFF) << 8) + (buf[3] & 0xFF);
			int rotate =  ((buf[4] & 0xFF) << 8) + (buf[5] & 0xFF);
			rotate = rotate/4;
			int speed = buf[6]&0xFF;  
			int temp = buf[7]&0xFF;
			Log.d("car", " voltage:"+voltage+" rotate:"+rotate+" speed"+speed+" temp:"+temp);
			
			handleVoltage(voltage);
			handleRotate(rotate);
			handleSpeed(speed);
			handleTemp(temp);
			
			int mileage = -1;
			if(buf[9] != (byte)0xFF || buf[8] != (byte)0xFF){
			     mileage = Data.byte2int(buf[9], buf[8]);    
			}
			Log.d("car", " mileage:"+mileage);
		    handleMileage(mileage);
		    
		    int remainGas = Data.byte2int(buf[12]);
			Log.d("car", " valid remainGas:"+remainGas);
			handleRemainGas(remainGas);
			
		}break;
		
		
		case 0x08:{
			byte[] szDstTemp = new byte[buf.length - 2];
			System.arraycopy(buf, 2, szDstTemp, 0, buf.length - 2);
			handleAllPid(szDstTemp, buf.length - 2);
		}break;
		case 0x09:
			handlePid(0x01, buf[2], buf[3], buf[4], buf[5]);
			break;
		case 0x0A:
			handlePid(0x21, buf[2], buf[3], buf[4], buf[5]);
			break;
		case 0x0B:
			handlePid(0x41, buf[2], buf[3], buf[4], buf[5]);
			break;
		case 0x0C:
			handlePid(0x61, buf[2], buf[3], buf[4], buf[5]);
			break;
		case 0x0D:
			handlePid(0x81, buf[2], buf[3], buf[4], buf[5]);
			break;
		case 0x0E:
			handlePid(0xA1, buf[2], buf[3], buf[4], buf[5]);
			break;
		case 0x0F:{
			if(buf[2] == 0){//start fast detect
		        Log.d("BT", "!!!!!!!on start fast detect!!!!"); 
		        ViewModel.getIns().setViewVisible(R.id.scan_car_view_parent, 1);
		        ViewModel.getIns().setViewVisible(R.id.fast_detect_car_listview_pid, 2);
		        
		        ViewModel.getIns().setViewProperty(R.id.scan_car_view,1);//startScan
			}else if(buf[2] == 1){//end fast detect
				Log.d("BT", "!!!!!!!on end fast detect !!!!");
				ViewModel.getIns().setViewProperty(R.id.scan_car_view,0);//startScan
				ViewModel.getIns().setViewVisible(R.id.scan_car_view_parent, 2);
				ViewModel.getIns().setViewVisible(R.id.fast_detect_car_listview_pid, 1);
				ViewModel.getIns().refreshView(R.id.fast_detect_car_listview_pid);
				/*public void refreshPidList()
				{
					mApp.getSinjetModel().getCarInfoModule().showPid();
					List<PID> pidListData = new ArrayList<PID>();
					pidListData.addAll(mApp.getSinjetModel().getCarInfoModule().getPidListData());
					 
					m_adapterPidList.setListData(pidListData);
				}*/
			}
		}break;
		case 0x12:{
			byte[] szDstTemp = new byte[buf.length - 2];
			System.arraycopy(buf, 2, szDstTemp, 0, buf.length - 2);
			getMonitorErrInfo(szDstTemp, buf.length-2);
		}break;
		case 0x1A:{
           int errCount = ((buf[2] & 0xFF) << 8) + (buf[3] & 0xFF);
   		   int voltage = ((buf[4] & 0xFF) << 8) + (buf[5] & 0xFF);
   		   int solarTermDoor = (buf[6] & 0xFF);
   		   int waterTemperature = (buf[7] & 0xFF);
   		   //nMonitorTurnSpeed = ((b5 & 0xFF) << 8) + (b6 & 0xFF);
   		   int threeCatalystTemperatureBankOne1 = (((buf[8] & 0xFF) << 8) + (buf[9] & 0xFF)) / 10 - 40;
   		   int threeCatalystTemperatureBankOne2 = (((buf[10] & 0xFF) << 8) + (buf[11] & 0xFF)) / 10 - 40;
   		   int threeCatalystTemperatureBankTwo1 = (((buf[12] & 0xFF) << 8) + (buf[13] & 0xFF)) / 10 - 40;
   		   int threeCatalystTemperatureBankTwo2 = (((buf[14] & 0xFF) << 8) + (buf[15] & 0xFF)) / 10 - 40;
   		   getCarConditionData(errCount,voltage,solarTermDoor,waterTemperature,threeCatalystTemperatureBankOne1,
   				threeCatalystTemperatureBankOne2,threeCatalystTemperatureBankTwo1,threeCatalystTemperatureBankTwo2);
		   }break;
		case 0x21:{
			int gearPUnlock = Data.byteH4(buf[2]);
			int gearDLock = Data.byteL4(buf[2]);
			onCarLockFunctionState(gearPUnlock,gearDLock);
		  }break;
		}
	}
	
	int mLeftFront = 0,mRightFront = 0,mLeftRear = 0,mRightRear = 0,mTrunk = 0;
	private void handleDoorState(int leftFront, int rightFront, int leftRear, int rightRear,
			int trunk) {
		// TODO Auto-generated method stub
		if(mLeftFront==leftFront&&mRightFront==rightFront
				&&mLeftRear==leftRear&&mRightRear==rightRear&&mTrunk==trunk){
			return; //all door states is not changed
		}
		mLeftFront = leftFront;
		mRightFront = rightFront;
		mLeftRear = leftRear;
		mRightRear = rightRear;
		mTrunk = trunk;
		
		Log.d(tag, "onDoorState:"+leftFront+","+rightFront+","+leftRear+","+rightRear+","+trunk);
		int doorOpenNumber = 0;
		String voiceText = "";
		if(leftFront == 1){
			doorOpenNumber++;
			voiceText = "左前门没有关";
		}
		if(rightFront == 1){
			doorOpenNumber++;
			voiceText = "右前门没有关";
		}
		if(leftRear == 1){
			doorOpenNumber++;
			voiceText = "左后门没有关";
		}
		if(rightRear == 1){
			doorOpenNumber++;
			voiceText = "右后门没有关";
		}
		if(trunk == 1){
			doorOpenNumber++;
			voiceText = "后备箱打开";
		}
		if(doorOpenNumber >0){
//			AppModel.getInstance().onDoorState(leftFrontDoor,rightFrontDoor,leftRearDoor,rightRearDoor,trunk);
			ViewModel.getIns().showDoorWarnView(leftFront, rightFront, leftRear, rightRear, trunk);
			if(doorOpenNumber == 1){
				if(AppModel.getInstance().getSettings().mDoorVoiceOn==1)
					;
//				BaiduTTSModel.getInstance(context).playText(voiceText);
			}else {
				if(AppModel.getInstance().getSettings().mDoorVoiceOn==1)
					;
//				BaiduTTSModel.getInstance(context).playText("多个门没有关");
			}
		}else{//all doors are close
			ViewModel.getIns().showDoorWarnView(0,0,0,0,0);
		}
	}

	int mRemainGas = -1;
	private void handleRemainGas(int remainGas) {
		// TODO Auto-generated method stub
		if(mRemainGas != remainGas){
			mRemainGas = remainGas;
			String textGas = "N/A";
			if(remainGas >=0 && remainGas<255)
			   textGas = ""+(int)remainGas*100/255+"%";
			ViewModel.getIns().setViewProperty(R.id.meter_gas_value, textGas);
		}
	}

	int mMileage = -1;
	private void handleMileage(int mileage) {
		// TODO Auto-generated method stub
		if(mMileage != mileage){
			mMileage = mileage;
			String textMileage = "N/A";
			if(mileage >=0 )
				textMileage = ""+mileage+"Km";
			ViewModel.getIns().setViewProperty(R.id.meter_mileage_value, textMileage);
		}
	}


	int mHandBrake = -1;
	int mSeatbelt = -1;
	int mGear = -1;
	int mGearNum = -1;
	private void handCarInfo(int handBrake, int seatbelt, int gear, int gearNum) {
		// TODO Auto-generated method stub
		//handbrake 0 :up  1:down
		if(mHandBrake != handBrake){
			mHandBrake = handBrake;
			int visible = (handBrake == 1)?1:0;
			ViewModel.getIns().setViewVisible(R.id.meter_handbrake, visible);
		}
		
		if(mSeatbelt != seatbelt){
			mSeatbelt = seatbelt;
			int visible = (seatbelt == 0)?1:0;
			ViewModel.getIns().setViewVisible(R.id.meter_seatbelt, visible);
		}
		
		if(mGear != gear || mGearNum != gearNum){
			mGear = gear;
			mGearNum = gearNum;
			String textGear = makeGearText(gear,gearNum);
			ViewModel.getIns().setViewProperty(R.id.meter_gear, textGear);
		}
	}

	String makeGearText(int gear,int gearNum){
		String result = "";
		switch(gear){
		case 0:
			break;
		case 1:
			result = "P";
			break;
		case 2:
			result = "R";
			break;
		case 3:
			result = "N";
			break;
		case 4:
			result = "D"+gearNum;
			break;
		case 5:
			result = "S";
			break;
		case 6:
			result = "M";
			break;
		case 9:
			result = "L"+gearNum;
			break;
		}
		return result;
	}

	byte[] SpeedAdjustArr = { 100, 102, 104, 106, 108, 110, 111, 112, 113, 114 };
	public void handleAllPid(byte[] p, int len) {
		int pid = p[0] & 0xFF;

		XJPIDDATA t =  getObdData().mSupportPIDMap.get(pid);
		if(t == null)
			return;
		switch (len) {
		case 2:
			if (pid == 0x0D) {
				t.A = (p[1] & 0xFF)
						* (SpeedAdjustArr[AppModel.getInstance().getSettings().speedAjust] & 0xFF)
						/ 100;
			} else {
				t.A = p[1] & 0xFF;
			}
			break;
		case 3:
			if (pid == 0x0D) {
				t.A = (p[1] & 0xFF)
						* (SpeedAdjustArr[AppModel.getInstance().getSettings().speedAjust] & 0xFF)
						/ 100;
			} else {
				t.A = p[1] & 0xFF;
			}
			t.B = p[2] & 0xFF;
			break;
		case 4:
			if (pid == 0x0D) {
				t.A = (p[1] & 0xFF)
						* (SpeedAdjustArr[AppModel.getInstance().getSettings().speedAjust] & 0xFF)
						/ 100;
			} else {
				t.A = p[1] & 0xFF;
			}
			t.B = p[2] & 0xFF;
			t.C = p[3] & 0xFF;
			break;
		case 5:
			if (pid == 0x0D) {
				t.A = (p[1] & 0xFF)
						* (SpeedAdjustArr[AppModel.getInstance().getSettings().speedAjust] & 0xFF)
						/ 100;
			} else {
				t.A = p[1] & 0xFF;
			}

			t.B = p[2] & 0xFF;
			t.C = p[3] & 0xFF;
			t.D = p[4] & 0xFF;
			break;
		}

		if (pid == 0x0D) {
			/*sendOneBroadcast(CarInfoDefine.ACTION_CAR_SPEED_TEST_SPEED,
					String.format("%d", t.A));*/
		}

	}
	private void getDevType(int type) {
		// TODO Auto-generated method stub
		models.controlModule.onCarModel(type);
		switch(type){
		case 0x00://default  tourebox
//			mNaviCodec.setIsHudDev(false);
			break;
		case 0x01:
		case 0x02:
		case 0x03:
//			mNaviCodec.setIsHudDev(true);
			break;
		}
	}

	private void getMonitorErrInfo(byte[] p,int len){
		int nMonitorErrorNum = p[0] & 0xFF;
		if (0xFF == nMonitorErrorNum) {//meaning start
			Log.d("ing", "clear old err");
			getObdData().getDectectedErrObdList().clear();
		} else if (0x00 == nMonitorErrorNum) {//meaning end 
			 ViewModel.getIns().refreshView(R.id.obd_search_listview_obd);
		} else {
			int i = 0;
			byte[] szCode = new byte[2];
			for (i = 1; i < len; i += 2) {
				byte[] szErrorCode = new byte[5];

				szCode[0] = p[i];
				szCode[1] = p[i + 1];
				byte b0 = szCode[0];
				byte b1 = szCode[1];

				int t = b0 & 0xC0;
				switch (t) {
				case 0x00:
					szErrorCode[0] = 'P';
					break;
				case 0x40:
					szErrorCode[0] = 'C';
					break;
				case 0x80:
					szErrorCode[0] = 'B';
					break;
				case 0xC0:
					szErrorCode[0] = 'U';
					break;
				}

				t = b0 & 0x30;
				switch (t) {
				case 0x00:
					szErrorCode[1] = '0';
					break;
				case 0x10:
					szErrorCode[1] = '1';
					break;
				case 0x20:
					szErrorCode[1] = '2';
					break;
				case 0x30:
					szErrorCode[1] = '3';
					break;
				}

				t = b0 & 0x0F;
				szErrorCode[2] = int2Byte(t);
				t = (b1 & 0xF0) >> 4;
				szErrorCode[3] = int2Byte(t);
				t = (b1 & 0x0F);
				szErrorCode[4] = int2Byte(t);
				 String strErrCode = new String(szErrorCode);
				 List<String> lstError = getObdData().getDectectedErrObdList();
				 if(!lstError.contains(strErrCode))
				 getObdData().getDectectedErrObdList().add(strErrCode);
			}
		}
		
	}

	private byte int2Byte(int i){
		if(i >= 0x00 && i <= 0x09) return (byte)('0'+i);
		else if(i >= 0x0A && i <= 0x0F) return (byte)('A'+i);
		return 0;
	}
	
    private void getOBDProtocolType(int type) {
		// TODO Auto-generated method stub
		String strObdType = "unknow";
		switch(type){
		case 0:
			strObdType = "NO_TYPE";
			break;
		case 1:
			strObdType = "J1850_PWM";
			break;
		case 2:
			strObdType = "J1850_VPW";
			break;
		case 3:
			strObdType = "ISO9141_2";
			break;
		case 4:
			strObdType = "ISO14230_5BAUD";
			break;
		case 5:
			strObdType = "ISO14230_FAST";
			break;
		case 6:
			strObdType = "ISO15765_500K_11BIT";
			break;
		case 7:
			strObdType = "ISO15765_500K_29BIT";
			break;
		case 8:
			strObdType = "ISO15765_250K_11BIT";
			break;
		case 9:
			strObdType = "ISO15765_250K_29BIT";
			break;
		default:
			strObdType = "unknow";
			break;
		}
		ViewModel.getIns().setViewProperty(R.id.car_obd_type_value, strObdType);
	}

	public int mErrCount = -1;
    public int mVoltage = -1;
    public int mSolarTermDoor = -1;
    public int mWaterTemperature = -1;
    public int mThreeCatalystTemperatureBankOne1 = -1;
    public int mThreeCatalystTemperatureBankOne2 = -1;
    public int mThreeCatalystTemperatureBankTwo1 = -1;
    public int mThreeCatalystTemperatureBankTwo2 = -1;
    public String mMemission = "";
	private void getCarConditionData(int errCount, int voltage, int solarTermDoor, int waterTemperature,
			int threeCatalystTemperatureBankOne1, int threeCatalystTemperatureBankOne2,
			int threeCatalystTemperatureBankTwo1, int threeCatalystTemperatureBankTwo2) {
		mErrCount = errCount;
		mVoltage = voltage;
		mSolarTermDoor = solarTermDoor;
		mWaterTemperature = waterTemperature;
		mThreeCatalystTemperatureBankOne1 = threeCatalystTemperatureBankOne1;
		mThreeCatalystTemperatureBankOne2 = threeCatalystTemperatureBankOne2;
		mThreeCatalystTemperatureBankTwo1 = threeCatalystTemperatureBankTwo1;
		mThreeCatalystTemperatureBankTwo2 = threeCatalystTemperatureBankTwo2;
		
		// TODO Auto-generated method stub
		ViewModel.getIns().setViewProperty(R.id.err_count_value, String.valueOf(errCount));
		ViewModel.getIns().setViewProperty(R.id.err_detected_count,String.valueOf(errCount));
		ViewModel.getIns().setViewProperty(R.id.system_power_supply_value, String.format("%.1fV", voltage / 1000.0));
		ViewModel.getIns().setViewProperty(R.id.system_air_intake_value, String.format("%.1f",solarTermDoor * 100 / 255.0) + "%");
//		ViewModel.getIns().setViewProperty(R.id.system_idling_value, String.format("%d°C", waterTemperature - 40));
		if(waterTemperature > 0 && waterTemperature != 255)
		     ViewModel.getIns().setViewProperty(R.id.system_cooling_value, String.format("%d°C", waterTemperature - 40));
		else 
			ViewModel.getIns().setViewProperty(R.id.system_cooling_value, "N/A");
		int pidData[] = new int[]{-1,-1,-1,-1};
		if(getObdData().mSupportPIDMap.get(0x3C).support == 1)
			pidData[0] = threeCatalystTemperatureBankOne1;
		if(getObdData().mSupportPIDMap.get(0x3D).support == 1)
			pidData[1] = threeCatalystTemperatureBankOne2;
		if(getObdData().mSupportPIDMap.get(0x3E).support == 1)
			pidData[2] = threeCatalystTemperatureBankTwo1;
		if(getObdData().mSupportPIDMap.get(0x3F).support == 1)
			pidData[3] = threeCatalystTemperatureBankTwo2;
		
		boolean isNormal = true;
		String memission = "";
		for(int i=0;i<pidData.length;i++){
			if(pidData[i] != -1) {
				memission = String.format(Locale.getDefault(),"%d°C",pidData[i]);
				break;
			}
		}
		ViewModel.getIns().setViewProperty(R.id.system_memissions_value, memission);
		mMemission = memission;
		
		if(mErrCount >0) isNormal = false;
		if(mVoltage != -1){
		    float fVoltage = mVoltage/1000.0f;
//		    if(!(fVoltage >= 10.0f && fVoltage <= 15.0f))
//		    	isNormal = false;
		}
		if(mSolarTermDoor != -1){
			float fSolarTermDoor = mSolarTermDoor*100.0f/255.0f;
//			if(!(fSolarTermDoor >= 20.7 && fSolarTermDoor <= 27.6))
//				isNormal = false;
		}
		if(mWaterTemperature != -1){
			int iWaterTemperature = mWaterTemperature - 40;
//			if(!(iWaterTemperature>=0&&iWaterTemperature<=112))
//				isNormal = false;
		}
		
		if(isNormal)  ViewModel.getIns().setViewProperty(R.id.car_condition_img_result, 1);
		else ViewModel.getIns().setViewProperty(R.id.car_condition_img_result, 2);
		
	}

	private void onRecvHudMsg(byte[] buf){
//		mNaviCodec.setIsHudDev(true);
		int cmd = buf[1];
		switch(cmd){
		case 0x07:
			int param = buf[2];
			if(param == 0x0) {
				//query time    
				syncTime();
			}else if(param == 0x1){
				isTimeSync = true;
			}
		}
	}
	
	
    private void handlePid(int from, byte a, byte b, byte c, byte d){
    	getObdData().handlePid(from, a, b, c, d);
    }

    
    int mMeterVoltage = -1;
    int mMeterRotate = -1;
    int  mSpeed = -1;
    int mTemp = -1;
    void handleVoltage(int voltage){
    	if(mMeterVoltage == voltage)
    		return;
    	mMeterVoltage = voltage;
    	DecimalFormat decimalFormat=new DecimalFormat(".0");
		float fVoltage = voltage/1000.0f;
		if(fVoltage > 0.0f){
			if(mRotate >350 && fVoltage < VOLTAGE_RANGE_MIN){//lower than normal
				onVoltageUnnormal(-1);
			}else if(fVoltage > VOLTAGE_RANGE_MAX){//higher than normal
				onVoltageUnnormal(1);
			}else{//it is normal
				if(mVoltageWarningTimes >0)
					mVoltageWarningTimes = 0;
			}
		    String strVoltage = decimalFormat.format(fVoltage);
		    ViewModel.getIns().setViewProperty(R.id.meter_voltage_value,strVoltage+"V");
		}else{
			ViewModel.getIns().setViewProperty(R.id.meter_voltage_value,"N/A");
		}
    }
    
    long mTimeOfLastVoltageWarning = 0;
    int mVoltageWarningTimes = 0;
    void onVoltageUnnormal(int highOrLowFlag){
    	if(AppModel.getInstance().getSettings().mVoltageVoiceOn == 0)
    		return;
    	if(mVoltageWarningTimes > 3) return;
    	
    	long currentTime = System.currentTimeMillis();
    	if(mTimeOfLastVoltageWarning == 0 || 
    			(currentTime - mTimeOfLastVoltageWarning>3*60*1000)){//3 minutes
    		mTimeOfLastVoltageWarning = currentTime; 
    		//warn again
    		mVoltageWarningTimes++;
    		if(highOrLowFlag == 1)  ;//BaiduTTSModel.getInstance(context).playText("电瓶电压偏高");
    		else if(highOrLowFlag == -1) ;//BaiduTTSModel.getInstance(context).playText("电瓶电压偏低");
    	}
    }

    
    void handleRotate(int rotate){
    	if(mMeterRotate == rotate)
    		return;
    	mMeterRotate = rotate;
    	if(rotate >=0 && rotate <= 8000){
//			int rotateDegree = (int)(rotate*15/1000.0f);
			mRotate = rotate;
			ViewModel.getIns().setViewProperty(R.id.system_idling_value, String.format("%dr/min", rotate));
			ViewModel.getIns().setViewProperty(R.id.meter_rotate_value, String.valueOf(mRotate));
//			ViewModel.getIns().setViewProperty(R.id.meter_rotate_meter, rotateDegree);
		}
    }
    
    void handleSpeed(int speed){
    	if(mSpeed == speed)
    		return;
    	mSpeed = speed;
    	if(speed >=0 && speed <=240){
			int speedDegree = speed;
			ViewModel.getIns().setViewProperty(R.id.meter_speed_meter, speedDegree);
			ViewModel.getIns().setViewProperty(R.id.meter_speed_value, String.valueOf(speed));
			if(speed >= 1)
				onCarMoving();
		}
    	
    }
    
    long mTimeOfLastWarnHandbrake = 0;
    long mTimeOfLastWarnSeatbelt = 0;
    
    void onCarMoving(){
         if(AppModel.getInstance().getSettings().mHandbrakeVoiceOn==1){
               if(mHandBrake == 1){
            	   if(mTimeOfLastWarnHandbrake == 0||
            			   (System.currentTimeMillis() - mTimeOfLastWarnHandbrake > 15*1000)){
            		   mTimeOfLastWarnHandbrake = System.currentTimeMillis();
            		   //BaiduTTSModel.getInstance(context).playText("请放下手刹");
            	   }
               }
         }
         if(AppModel.getInstance().getSettings().mSeatbeltVoiceOn == 1){
        	 if(mSeatbelt == 0){//not bulked lock
        		 if(mTimeOfLastWarnSeatbelt == 0 ||
        				 (System.currentTimeMillis()-mTimeOfLastWarnSeatbelt>30*1000)){
        			 mTimeOfLastWarnSeatbelt = System.currentTimeMillis();
        			 //BaiduTTSModel.getInstance(context).playText("请系好安全带");
        		 }
        	 }
         }
    }
    
	private void handleTemp(int temp) {
		// TODO Auto-generated method stub
        if(mTemp == temp)
        	return;
        mTemp = temp;
		if(temp>=0 && temp != 255){
		    int temperature = temp+(-40);
		    ViewModel.getIns().setViewProperty(R.id.meter_temp_value,String.valueOf(temperature)+"℃");
		     if(temperature<TEMPERATURE_RANGE_MIN){
		    	 onWaterTemperatureUnnormal(-1);
		     }else if(temperature>TEMPERATURE_RANGE_MAX){
		    	 onWaterTemperatureUnnormal(1);
		     }else{//it is normal
		    	 if(mTemperatureWarnTimes >0)
		    		 mTemperatureWarnTimes = 0;
		     }
		}else{
			ViewModel.getIns().setViewProperty(R.id.meter_temp_value,"N/A");
		}
	}
	
	
	
	long mTimeOfLastWarnTemperature = 0;
	int mTemperatureWarnTimes = 0;
    void onWaterTemperatureUnnormal(int highOrLowFlag){
    	if(AppModel.getInstance().getSettings().mTempVoiceOn == 0)
    		return;
    	if(mTemperatureWarnTimes > 3) return;
    	long currentTime = System.currentTimeMillis();
    	if(mTimeOfLastWarnTemperature == 0||
    			(currentTime - mTimeOfLastWarnTemperature > 3*60*1000)){//warn 3 straight times every 3 minutes
    		mTimeOfLastWarnTemperature  = currentTime;
    		mTemperatureWarnTimes ++;
    		if(highOrLowFlag == -1)
    			;//BaiduTTSModel.getInstance(context).playText("水温偏低");
    		else if(highOrLowFlag == 1)
    			;//BaiduTTSModel.getInstance(context).playText("水温偏高");
    	}
    }
    
    
	public void onViewEvent(ViewEvent event){
		   Log.i("view", "onViewEvent:"+event.getTag());
//		   showPasswordPannel();
		   int id = event.getTag();
		   switch(id){
		   case R.id.gear_d_lock_onoff:
			   onClkGearDLock();
			   break;
			case R.id.gear_p_unlock_onoff:
				onClkGearPUnlock();
			   break;
		   }
    }
	
	
	
	
	
	int mGearFunOnoffVisible = 0;
	int mGearDLock = 0;
	int mGearPUnlock = 0;
    private void onCarLockFunctionState(int gearPUnlock,int gearDLock){
    	 Log.d(tag, "onCarLockFunc:"+gearPUnlock+","+gearDLock);
    	 if(mGearFunOnoffVisible == 0){
    		 ViewModel.getIns().setViewVisible(R.id.gear_d_lock, 1);
        	 ViewModel.getIns().setViewVisible(R.id.gear_p_unlock, 1);
        	 mGearFunOnoffVisible = 1;
    	 }
    	 
    	 if(mGearPUnlock != gearPUnlock){
    		 mGearPUnlock = gearPUnlock;
    		 int onOff = (gearPUnlock==1)?1:0;
    		 ViewModel.getIns().setViewProperty(R.id.gear_p_unlock_onoff, onOff);
    	 }
    	 if(mGearDLock != gearDLock){
    		 mGearDLock = gearDLock;
    		 int onOff = (gearDLock ==1)?1:0;
    		 ViewModel.getIns().setViewProperty(R.id.gear_d_lock_onoff, onOff);
    	 }
    }
	void onClkGearDLock(){
	   if(mGearDLock == 1) mGearDLock = 0;
	   else mGearDLock = 1;
	   ViewModel.getIns().setViewProperty(R.id.gear_d_lock_onoff, mGearDLock);
	   sendGearFunSet(mGearDLock, mGearPUnlock);
   }
   void onClkGearPUnlock(){
	   if(mGearPUnlock == 1) mGearPUnlock = 0;
	   else mGearPUnlock = 1;
	   ViewModel.getIns().setViewProperty(R.id.gear_p_unlock_onoff, mGearPUnlock);
	   sendGearFunSet(mGearDLock, mGearPUnlock);
   }
   
   void sendGearFunSet(int DLock,int PUnlock){
	   byte H4 = (byte) (PUnlock&0x0F);
	   byte L4 = (byte)(DLock&0x0F);
	   byte setByte = (byte)(H4<<4|L4);
	   byte[] buf = new byte[]{0x21,setByte};
	   packAndSendMsg(buf, buf.length);
   }
   
   
   
   private void packAndSendMsg(byte[] message,int len){
	    byte[] szMsg = new byte[len + 5];
		szMsg[0] = (byte) 0xFF;
		szMsg[1] = (byte) 0x55;
		szMsg[2] = (byte) (len + 1);
		szMsg[3] = (byte) 0x03;
		System.arraycopy(message, 0, szMsg, 4, len);

		byte sum = 0;
		int s = 0;
		int i = 0;
		for (i = 2; i < len + 4; i++) {
			s += (szMsg[i] & 0xFF);
		}
		sum = (byte) (s & 0xFF);
		szMsg[len + 4] = sum;
		BluetoothModel.getInstance().sendMessage(szMsg);
  }
   
	String strMCUUUID = null;
	public String getMcuUUID(){
		return strMCUUUID;
	}
	public void setMcuUUID(String uuid){
		if (strMCUUUID == null || !strMCUUUID.equals(uuid))
		{
			strMCUUUID = uuid;
			AppModel.getInstance().uploadToServiceAnsy();
		}
	}
	
	int moduleUpgradeMethod = 0;
	public int getMCUUpgradeMethod() {
		return moduleUpgradeMethod;
	}
	public void setMCUUpgradeMethod(int method) {
		moduleUpgradeMethod = method;
	}
}